package com.bizframework.springhb.support.util;

import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

import com.bizframework.core.domain.QueryCondition;
import com.bizframework.core.domain.QueryOperator;
import com.bizframework.core.domain.SortInfo;
import com.bizframework.core.util.StringUtils;

import org.apache.commons.lang.time.DateUtils;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.proxy.HibernateProxy;

public class Utils {

	public static Object getProxyTarget(Object obj) {
		if (obj instanceof HibernateProxy) {
			Object target = ((HibernateProxy) obj)
					.getHibernateLazyInitializer().getImplementation();
			return target;
		} else {
			return obj;
		}
	}

	public static Query createQuery(Session session, String hql,
			HashMap<String, String> conditionFieldMap, String defalutAlias,
			List<QueryCondition> conditions, SortInfo sortInfo)
			throws Exception {
		String conditonString = "";
		if (conditions != null) {
			for (QueryCondition condition : conditions) {
				if (condition == null)
					continue;

				String c = "";
				String field = defalutAlias + "." + condition.getFieldName();
				if (conditionFieldMap != null
						&& conditionFieldMap.containsKey(condition
								.getFieldName())) {
					field = conditionFieldMap.get(condition.getFieldName());
				}

				String paraName = defalutAlias + "_" + condition.getFieldName()
						+ condition.hashCode();
				paraName = paraName.replace(".", "_");
				if (condition.getFieldValueString() == null
						&& condition.getFieldValue() == null) {
					if (condition.getQueryOperator() == QueryOperator.Equal) {
						c = "{0} is null".replace("{0}", field).replace("{1}",
								":" + paraName);
					} else if (condition.getQueryOperator() == QueryOperator.NoEqual) {
						c = "{0} is not null".replace("{0}", field).replace(
								"{1}", ":" + paraName);
					}
				} else {
					switch (condition.getFieldType()) {
					case Date:
						if (condition.getQueryOperator().equals(
								QueryOperator.Equal)) {
							c = "({0}>={1} and {0}<{2})".replace("{0}", field)
									.replace("{1}", ":" + paraName + "_b")
									.replace("{2}", ":" + paraName + "_e");
						} else {
							c = condition.getQueryOperator()
									.replace("{0}", field)
									.replace("{1}", ":" + paraName);
						}
						break;
					default:
						c = condition.getQueryOperator().replace("{0}", field)
								.replace("{1}", ":" + paraName);
						break;
					}
				}
				if (StringUtils.isNullOrEmpty(conditonString)) {
					conditonString += " " + c;
				} else {
					conditonString += " " + condition.getQueryLogic() + " " + c;
				}
			}
		}
		if (!StringUtils.isNullOrEmpty(conditonString)) {
			hql += " and (" + conditonString + ")";
		}

		if (sortInfo != null) {
			if (sortInfo.getName() != null && sortInfo.getName() != "") {
				String dir = sortInfo.getSortDirection().toString();

				String sortField = defalutAlias + "." + sortInfo.getName();
				if (conditionFieldMap != null
						&& conditionFieldMap.containsKey(sortInfo.getName())) {
					sortField = conditionFieldMap.get(sortInfo.getName());
				}
				hql += " Order By " + sortField + " " + dir;
			}
		}

		Query query = session.createQuery(hql.toString());
		if (conditions != null) {
			for (QueryCondition condition : conditions) {
				if (condition == null)
					continue;

				String paraName = defalutAlias + "_" + condition.getFieldName()
						+ condition.hashCode();
				paraName = paraName.replace(".", "_");
				if (condition.getFieldValueString() != null
						|| condition.getFieldValue() != null) {
					if (condition.getQueryOperator() == QueryOperator.In) {
						if (condition.getFieldValue() instanceof Collection<?>) {
							query.setParameterList(paraName,
									(Collection<?>) condition.getFieldValue());
						} else if (condition.getFieldValue() instanceof Object[]) {
							query.setParameterList(paraName,
									(Object[]) condition.getFieldValue());
						}
					} else {
						switch (condition.getFieldType()) {
						case Date:
							if (condition.getQueryOperator().equals(
									QueryOperator.Equal)) {
								Date v = (Date) condition
										.parseFieldValueString();
								query.setParameter(paraName + "_b", v);
								query.setParameter(paraName + "_e",
										DateUtils.addDays(v, 1));
							} else {
								query.setParameter(paraName,
										condition.parseFieldValueString());
							}
						case Boolean:
							break;
						default:
							query.setParameter(paraName,
									condition.parseFieldValueString());
							break;
						}

					}
				}
			}
		}
		return query;
	}
}